/**
 * @license
 * Copyright 2017 Google Inc. All rights reserved.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

goog.module('e2e.transparency.merkleTest');
goog.setTestOnly();

/** @suppress {extraRequire} */
const asserts = goog.require('goog.testing.asserts');
const e2e = goog.require('e2e');
/** @suppress {extraRequire} */
const jsunit = goog.require('goog.testing.jsunit');
const merkle = goog.require('e2e.transparency.merkle');
const testSuite = goog.require('goog.testing.testSuite');
const {byteArrayToHex, hexToByteArray} = goog.require('goog.crypt');


/**
 * Returns a ByteArray of the specified length with all bits unset.
 *
 * @param {number} length
 * @return {!e2e.ByteArray}
 */
function zeroes(length) {
  const result = new Array(length);
  for (let i = 0; i < length; i++) {
    result[i] = 0x00;
  }
  return result;
}

/**
 * Returns a ByteArray of the specified length with all bits set.
 *
 * @param {number} length
 * @return {!e2e.ByteArray}
 */
function ones(length) {
  const result = new Array(length);
  for (let i = 0; i < length; i++) {
    result[i] = 0xff;
  }
  return result;
}

/**
 * Returns a ByteArray that is [0x00, 0x01, 0x02, ...].
 *
 * @param {number} length
 * @return {!e2e.ByteArray}
 */
function sequential(length) {
  const result = new Array(length);
  for (let i = 0; i < length; i++) {
    result[i] = i;
  }
  return result;
}

/**
 * Returns a ByteArray with alternating 0 and 1 bits set.
 *
 * @param {number} length
 * @return {!e2e.ByteArray}
 */
function alternating(length) {
  const result = new Array(length);
  for (let i = 0; i < length; i++) {
    result[i] = 0x55;
  }
  return result;
}


testSuite({
  testIsBitSet() {
    const zeroesIndex = new merkle.TreeIndex(zeroes(32));
    const onesIndex = new merkle.TreeIndex(ones(32));
    for (let i = 0; i < 256; i++) {
      assertFalse(zeroesIndex.isBitSet(i));
      assertTrue(onesIndex.isBitSet(i));
    }
    // 0b010101010101...
    const alternatingIndex = new merkle.TreeIndex(alternating(32));
    for (let i = 0; i < 256; i += 2) {
      assertFalse(alternatingIndex.isBitSet(i));
      assertTrue(alternatingIndex.isBitSet(i + 1));
    }
  },

  testMaskIndex() {
    const testCases = [
      {
        index: ones(32),
        height: 256,
        want: zeroes(32),
      },
      {index: ones(32), height: 255, want: [0x80].concat(zeroes(31))},
      {index: ones(32), height: 254, want: [0xC0].concat(zeroes(31))},
      {index: ones(32), height: 253, want: [0xE0].concat(zeroes(31))},
      {index: ones(32), height: 252, want: [0xF0].concat(zeroes(31))},
      {index: ones(32), height: 251, want: [0xF8].concat(zeroes(31))},
      {index: ones(32), height: 250, want: [0xFC].concat(zeroes(31))},
      {index: ones(32), height: 249, want: [0xFE].concat(zeroes(31))},
      {index: ones(32), height: 248, want: [0xFF].concat(zeroes(31))},
      {index: ones(32), height: 247, want: [0xFF, 0x80].concat(zeroes(30))},
      {index: ones(32), height: 246, want: [0xFF, 0xC0].concat(zeroes(30))},
      {index: ones(32), height: 0, want: ones(32)},
      {index: ones(32), height: 1, want: ones(31).concat([0xFE])},
      {index: ones(32), height: 96, want: ones(20).concat(zeroes(12))}, {
        index: sequential(32),
        height: 255,
        want: zeroes(32),
      },
      {
        index: sequential(32),
        height: 239,
        want: [0x00, 0x01].concat(zeroes(30))
      },
      {
        index: sequential(32),
        height: 97,
        want: Array.prototype.concat.apply(
            [], [sequential(19), [0x12], zeroes(12)])
      },
      {
        index: sequential(32),
        height: 96,
        want: sequential(20).concat(zeroes(12))
      }
    ];
    for (const testCase of testCases) {
      const indexObj = new merkle.TreeIndex(testCase.index);
      const result = indexObj.mask(testCase.height);
      assertArrayEquals(
          'index = ' + byteArrayToHex(testCase.index) + ', ' +
              'height = ' + testCase.height,
          testCase.want, result.bytes());
    }
  },

  testAscentSiblings() {
    const index = new merkle.TreeIndex(sequential(32));
    const result = index.ascentSiblings();
    for (let i = 0; i < 256; i++) {
      assertArrayEquals(
          'height = ' + i, EXPECTED_SEQUENTIAL_SIBLINGS_[i], result[i].bytes());
    }
  },

  testHashLeaf() {
    // Copied from
    // https://github.com/google/trillian/blob/master/merkle/coniks/coniks_test.go.
    const testCases = [
      {
        treeId: zeroes(8),
        index: zeroes(32),
        leafData: [],
        want: hexToByteArray(
            'b4e04ff32be7f76c9621dd28946c261dd8aea6494bf713c03da75dd9f1ce2fec')
      },
      {
        treeId: e2e.dwordArrayToByteArray([0, 1]),
        index: zeroes(32),
        leafData: [],
        want: hexToByteArray(
            '83800c063525c35afdfe60733fb631be976d06835f79e9914dd268ec2f313721')
      },
      {
        treeId: zeroes(8),
        index: hexToByteArray(
            '1111111111111111111111111111111111111111111111111111111111111111'),
        leafData: [],
        want: hexToByteArray(
            '4a95b36a21da32aba1a32d05ae3a1ef200f896c82a7c5ad03da52b17fdcbeb37')
      },
      {
        treeId: zeroes(8),
        index: zeroes(32),
        leafData: e2e.stringToByteArray('foo'),
        want: hexToByteArray(
            'd1f7b835e5ed66fc564b5a9e0a7ca028a6e4ec85a6c7d9d96b2ad6d0c1369700')
      },
      {
        treeId: zeroes(8),
        index: hexToByteArray(
            '1111111111111111111111111111111111111111111111111111111111111111'),
        leafData: e2e.stringToByteArray('leaf'),
        want: hexToByteArray(
            '87f51e6ceb5a46947fedbd1de543482fb72f7459055d853a841566ef8e43c4a2')
      }
    ];
    for (const testCase of testCases) {
      const index = new merkle.TreeIndex(testCase.index);
      const result = merkle.hashLeaf(testCase.treeId, index, testCase.leafData);
      assertArrayEquals(
          'treeId = ' + byteArrayToHex(testCase.treeId) + ', ' +
              'index = ' + byteArrayToHex(testCase.index) + ', ' +
              'leafData = ' + byteArrayToHex(testCase.leafData),
          testCase.want, result);
    }
  },

  testHashEmpty() {
    // Copied from
    // https://github.com/google/trillian/blob/master/merkle/coniks/coniks_test.go.
    const testCases = [
      {
        treeId: zeroes(8),
        index: zeroes(32),
        height: 256,
        want: hexToByteArray(
            '2b71932d625e7b83ce864f8092ae4eb470670ccff37eaac83f21679bb3b24bbb')
      },
      {
        treeId: e2e.dwordArrayToByteArray([0, 1]),
        index: zeroes(32),
        height: 256,
        want: hexToByteArray(
            '9a908ed88f429272254a97c6a55f781e15b0cff753fb90ce7591988b398378ea')
      },
      {
        treeId: zeroes(8),
        index: hexToByteArray(
            '1111111111111111111111111111111111111111111111111111111111111111'),
        height: 255,
        want: hexToByteArray(
            'a9804d4c78c33a72903a5dc71a900a00e55136a425b6e4365c2d90f8303eb233')
      },
      {
        treeId: zeroes(8),
        index: zeroes(32),
        height: 0,
        want: hexToByteArray(
            'af8545ff33b365f2a45971abc45167634c17bfc883ff0280f56e542663b02417')
      }
    ];
    for (const testCase of testCases) {
      const index = new merkle.TreeIndex(testCase.index);
      const result = merkle.hashEmpty(testCase.treeId, index, testCase.height);
      assertArrayEquals(
          'treeId = ' + byteArrayToHex(testCase.treeId) + ', ' +
              'index = ' + byteArrayToHex(testCase.index) + ', ' +
              'height = ' + testCase.height,
          testCase.want, result);
    }
  },

  testHashChildren() {
    // Copied from
    // https://github.com/google/trillian/blob/master/merkle/coniks/coniks_test.go.
    const testCases = [
      {
        left: zeroes(32),
        right: hexToByteArray(
            '1111111111111111111111111111111111111111111111111111111111111111'),
        want: hexToByteArray(
            'c1c6101db394de0d197b6bd90406fa300d28fee7028c7b37406b16edb61cccb4')
      },
      {
        left: hexToByteArray(
            '1111111111111111111111111111111111111111111111111111111111111111'),
        right: zeroes(32),
        want: hexToByteArray(
            '4698c0cfa150974ad8d55e9c3f7d20dcdd56e7023931e1f7b5f61fbcf15770c3')
      }
    ];
    for (const testCase of testCases) {
      const result = merkle.hashChildren(testCase.left, testCase.right);
      assertArrayEquals(
          'left = ' + byteArrayToHex(testCase.left) + ', ' +
              'right = ' + byteArrayToHex(testCase.right),
          testCase.want, result);
    }
  },

  testInclusionProof() {
    // Copied from
    // https://github.com/google/trillian/blob/master/merkle/map_verifier_test.go.
    const testCases = [{
      description: 'Empty proof',
      treeId: hexToByteArray('54a71cdc68384108'),
      index: hexToByteArray(
          '6e39bd1b2aec80f29204d63b9aff74b17cc0255b8e9d6a8fc4c069cfefc01ce9'),
      leafData: hexToByteArray(
          '1290010a4030393264343162666564666665666639376261313963653430356' +
          '165633433383631333766373435376439303234633537663361333439366630' +
          '303938366538124c080410031a463044022064cf8e276381a5fc993e471e294' +
          '63dbebf99b7e361a389024a92c3cb0fa1571402200bb9af4bd2e61fa5e2ea46' +
          'cd1e653ee0f264703293d4ddd6bc88fc2cde5049181a206e39bd1b2aec80f29' +
          '204d63b9aff74b17cc0255b8e9d6a8fc4c069cfefc01ce932200f30aff51b69' +
          '6d25d423f0d0fa208efe6038d83133cdc58b8d68f9d30e029efc3a5d0a5b305' +
          '9301306072a8648ce3d020106082a8648ce3d03010703420004fb154e769864' +
          '7e912d97b385f280b2bd6c37d5d57886719b5c33db74594bd6799aca19eac84' +
          '7d1757365a414f653d857712c6588a235ac7ac02450f1de772db442201b16b1' +
          'df538ba12dc3f97edbb85caa7050d46c148134290feba80f8236c83db9'),
      proof: new Array(256).fill(null),
      root: hexToByteArray(
          '9986cc7a6ede7443a877cb8b971bb4cf8628ba30f41a002f6eb231fd093bb49f')
    }];
    for (const testCase of testCases) {
      const index = new merkle.TreeIndex(testCase.index);
      assertTrue(
          'test case ' + testCase.description,
          merkle.verifyInclusionProof(
              testCase.treeId, index, testCase.leafData, testCase.root,
              testCase.proof));
    }
  },

  testExclusionProof() {
    // Copied from
    // https://github.com/google/trillian/blob/master/merkle/map_verifier_test.go.
    const testCases = [
      {
        description: 'Empty proof',
        treeId: hexToByteArray('7f559c6c0df872dc'),
        index: hexToByteArray(
            'a5d137b43938ce3f2869554206b1964b8495daa25408f27575801ac071baeda7'),
        leafData: [],
        proof: new Array(256).fill(null),
        root: hexToByteArray(
            '0efc54ade0fce876558c9738f5aa89e4d99c0b8b6fe0b62dbf6359cfc2adbbd7')
      },
      {
        description: 'One item in tree',
        treeId: hexToByteArray('2405f03bbf96b4b2'),
        index: hexToByteArray(
            'b7572df6e1091fc0069e04bf80987525e77ac9a6c294d28db7f4e360251d83bf'),
        leafData: [],
        proof: new Array(255).fill(null).concat([
          hexToByteArray(
              '5cd70d71618ad69e0d1de343ec22d7044cbc4ff795dfe39356d65a7ec0d47140')
        ]),
        root: hexToByteArray(
            '2c2703e034f4002f941dfcea7a4e1603ee8b4ee375bdf8725eb8af04bfa3d156')
      }
    ];
    for (const testCase of testCases) {
      const index = new merkle.TreeIndex(testCase.index);
      assertTrue(
          'test case ' + testCase.description,
          merkle.verifyExclusionProof(
              testCase.treeId, index, testCase.root, testCase.proof));
    }
  },
});

// Expected results from calling ascentSiblings on a TreeIndex with
// 0x00010203....  Generated from a Python script, and placed at the end of the
// file for legibility.
const EXPECTED_SEQUENTIAL_SIBLINGS_ = [
  '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1e',
  '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1c',
  '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e18',
  '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e10',
  '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e00',
  '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e20',
  '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e40',
  '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e80',
  '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1f00',
  '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1c00',
  '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1800',
  '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1000',
  '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d0000',
  '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d2000',
  '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d4000',
  '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d8000',
  '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1c0000',
  '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1e0000',
  '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c180000',
  '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c100000',
  '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c000000',
  '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c200000',
  '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c400000',
  '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c800000',
  '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1d000000',
  '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1e000000',
  '000102030405060708090a0b0c0d0e0f101112131415161718191a1b18000000',
  '000102030405060708090a0b0c0d0e0f101112131415161718191a1b10000000',
  '000102030405060708090a0b0c0d0e0f101112131415161718191a1b00000000',
  '000102030405060708090a0b0c0d0e0f101112131415161718191a1b20000000',
  '000102030405060708090a0b0c0d0e0f101112131415161718191a1b40000000',
  '000102030405060708090a0b0c0d0e0f101112131415161718191a1b80000000',
  '000102030405060708090a0b0c0d0e0f101112131415161718191a1a00000000',
  '000102030405060708090a0b0c0d0e0f101112131415161718191a1800000000',
  '000102030405060708090a0b0c0d0e0f101112131415161718191a1c00000000',
  '000102030405060708090a0b0c0d0e0f101112131415161718191a1000000000',
  '000102030405060708090a0b0c0d0e0f101112131415161718191a0000000000',
  '000102030405060708090a0b0c0d0e0f101112131415161718191a2000000000',
  '000102030405060708090a0b0c0d0e0f101112131415161718191a4000000000',
  '000102030405060708090a0b0c0d0e0f101112131415161718191a8000000000',
  '000102030405060708090a0b0c0d0e0f101112131415161718191b0000000000',
  '000102030405060708090a0b0c0d0e0f10111213141516171819180000000000',
  '000102030405060708090a0b0c0d0e0f101112131415161718191c0000000000',
  '000102030405060708090a0b0c0d0e0f10111213141516171819100000000000',
  '000102030405060708090a0b0c0d0e0f10111213141516171819000000000000',
  '000102030405060708090a0b0c0d0e0f10111213141516171819200000000000',
  '000102030405060708090a0b0c0d0e0f10111213141516171819400000000000',
  '000102030405060708090a0b0c0d0e0f10111213141516171819800000000000',
  '000102030405060708090a0b0c0d0e0f10111213141516171818000000000000',
  '000102030405060708090a0b0c0d0e0f1011121314151617181a000000000000',
  '000102030405060708090a0b0c0d0e0f1011121314151617181c000000000000',
  '000102030405060708090a0b0c0d0e0f10111213141516171810000000000000',
  '000102030405060708090a0b0c0d0e0f10111213141516171800000000000000',
  '000102030405060708090a0b0c0d0e0f10111213141516171820000000000000',
  '000102030405060708090a0b0c0d0e0f10111213141516171840000000000000',
  '000102030405060708090a0b0c0d0e0f10111213141516171880000000000000',
  '000102030405060708090a0b0c0d0e0f10111213141516171900000000000000',
  '000102030405060708090a0b0c0d0e0f10111213141516171a00000000000000',
  '000102030405060708090a0b0c0d0e0f10111213141516171c00000000000000',
  '000102030405060708090a0b0c0d0e0f10111213141516171000000000000000',
  '000102030405060708090a0b0c0d0e0f10111213141516170000000000000000',
  '000102030405060708090a0b0c0d0e0f10111213141516172000000000000000',
  '000102030405060708090a0b0c0d0e0f10111213141516174000000000000000',
  '000102030405060708090a0b0c0d0e0f10111213141516178000000000000000',
  '000102030405060708090a0b0c0d0e0f10111213141516160000000000000000',
  '000102030405060708090a0b0c0d0e0f10111213141516140000000000000000',
  '000102030405060708090a0b0c0d0e0f10111213141516100000000000000000',
  '000102030405060708090a0b0c0d0e0f10111213141516180000000000000000',
  '000102030405060708090a0b0c0d0e0f10111213141516000000000000000000',
  '000102030405060708090a0b0c0d0e0f10111213141516200000000000000000',
  '000102030405060708090a0b0c0d0e0f10111213141516400000000000000000',
  '000102030405060708090a0b0c0d0e0f10111213141516800000000000000000',
  '000102030405060708090a0b0c0d0e0f10111213141517000000000000000000',
  '000102030405060708090a0b0c0d0e0f10111213141514000000000000000000',
  '000102030405060708090a0b0c0d0e0f10111213141510000000000000000000',
  '000102030405060708090a0b0c0d0e0f10111213141518000000000000000000',
  '000102030405060708090a0b0c0d0e0f10111213141500000000000000000000',
  '000102030405060708090a0b0c0d0e0f10111213141520000000000000000000',
  '000102030405060708090a0b0c0d0e0f10111213141540000000000000000000',
  '000102030405060708090a0b0c0d0e0f10111213141580000000000000000000',
  '000102030405060708090a0b0c0d0e0f10111213141400000000000000000000',
  '000102030405060708090a0b0c0d0e0f10111213141600000000000000000000',
  '000102030405060708090a0b0c0d0e0f10111213141000000000000000000000',
  '000102030405060708090a0b0c0d0e0f10111213141800000000000000000000',
  '000102030405060708090a0b0c0d0e0f10111213140000000000000000000000',
  '000102030405060708090a0b0c0d0e0f10111213142000000000000000000000',
  '000102030405060708090a0b0c0d0e0f10111213144000000000000000000000',
  '000102030405060708090a0b0c0d0e0f10111213148000000000000000000000',
  '000102030405060708090a0b0c0d0e0f10111213150000000000000000000000',
  '000102030405060708090a0b0c0d0e0f10111213160000000000000000000000',
  '000102030405060708090a0b0c0d0e0f10111213100000000000000000000000',
  '000102030405060708090a0b0c0d0e0f10111213180000000000000000000000',
  '000102030405060708090a0b0c0d0e0f10111213000000000000000000000000',
  '000102030405060708090a0b0c0d0e0f10111213200000000000000000000000',
  '000102030405060708090a0b0c0d0e0f10111213400000000000000000000000',
  '000102030405060708090a0b0c0d0e0f10111213800000000000000000000000',
  '000102030405060708090a0b0c0d0e0f10111212000000000000000000000000',
  '000102030405060708090a0b0c0d0e0f10111210000000000000000000000000',
  '000102030405060708090a0b0c0d0e0f10111214000000000000000000000000',
  '000102030405060708090a0b0c0d0e0f10111218000000000000000000000000',
  '000102030405060708090a0b0c0d0e0f10111200000000000000000000000000',
  '000102030405060708090a0b0c0d0e0f10111220000000000000000000000000',
  '000102030405060708090a0b0c0d0e0f10111240000000000000000000000000',
  '000102030405060708090a0b0c0d0e0f10111280000000000000000000000000',
  '000102030405060708090a0b0c0d0e0f10111300000000000000000000000000',
  '000102030405060708090a0b0c0d0e0f10111000000000000000000000000000',
  '000102030405060708090a0b0c0d0e0f10111400000000000000000000000000',
  '000102030405060708090a0b0c0d0e0f10111800000000000000000000000000',
  '000102030405060708090a0b0c0d0e0f10110000000000000000000000000000',
  '000102030405060708090a0b0c0d0e0f10112000000000000000000000000000',
  '000102030405060708090a0b0c0d0e0f10114000000000000000000000000000',
  '000102030405060708090a0b0c0d0e0f10118000000000000000000000000000',
  '000102030405060708090a0b0c0d0e0f10100000000000000000000000000000',
  '000102030405060708090a0b0c0d0e0f10120000000000000000000000000000',
  '000102030405060708090a0b0c0d0e0f10140000000000000000000000000000',
  '000102030405060708090a0b0c0d0e0f10180000000000000000000000000000',
  '000102030405060708090a0b0c0d0e0f10000000000000000000000000000000',
  '000102030405060708090a0b0c0d0e0f10200000000000000000000000000000',
  '000102030405060708090a0b0c0d0e0f10400000000000000000000000000000',
  '000102030405060708090a0b0c0d0e0f10800000000000000000000000000000',
  '000102030405060708090a0b0c0d0e0f11000000000000000000000000000000',
  '000102030405060708090a0b0c0d0e0f12000000000000000000000000000000',
  '000102030405060708090a0b0c0d0e0f14000000000000000000000000000000',
  '000102030405060708090a0b0c0d0e0f18000000000000000000000000000000',
  '000102030405060708090a0b0c0d0e0f00000000000000000000000000000000',
  '000102030405060708090a0b0c0d0e0f20000000000000000000000000000000',
  '000102030405060708090a0b0c0d0e0f40000000000000000000000000000000',
  '000102030405060708090a0b0c0d0e0f80000000000000000000000000000000',
  '000102030405060708090a0b0c0d0e0e00000000000000000000000000000000',
  '000102030405060708090a0b0c0d0e0c00000000000000000000000000000000',
  '000102030405060708090a0b0c0d0e0800000000000000000000000000000000',
  '000102030405060708090a0b0c0d0e0000000000000000000000000000000000',
  '000102030405060708090a0b0c0d0e1000000000000000000000000000000000',
  '000102030405060708090a0b0c0d0e2000000000000000000000000000000000',
  '000102030405060708090a0b0c0d0e4000000000000000000000000000000000',
  '000102030405060708090a0b0c0d0e8000000000000000000000000000000000',
  '000102030405060708090a0b0c0d0f0000000000000000000000000000000000',
  '000102030405060708090a0b0c0d0c0000000000000000000000000000000000',
  '000102030405060708090a0b0c0d080000000000000000000000000000000000',
  '000102030405060708090a0b0c0d000000000000000000000000000000000000',
  '000102030405060708090a0b0c0d100000000000000000000000000000000000',
  '000102030405060708090a0b0c0d200000000000000000000000000000000000',
  '000102030405060708090a0b0c0d400000000000000000000000000000000000',
  '000102030405060708090a0b0c0d800000000000000000000000000000000000',
  '000102030405060708090a0b0c0c000000000000000000000000000000000000',
  '000102030405060708090a0b0c0e000000000000000000000000000000000000',
  '000102030405060708090a0b0c08000000000000000000000000000000000000',
  '000102030405060708090a0b0c00000000000000000000000000000000000000',
  '000102030405060708090a0b0c10000000000000000000000000000000000000',
  '000102030405060708090a0b0c20000000000000000000000000000000000000',
  '000102030405060708090a0b0c40000000000000000000000000000000000000',
  '000102030405060708090a0b0c80000000000000000000000000000000000000',
  '000102030405060708090a0b0d00000000000000000000000000000000000000',
  '000102030405060708090a0b0e00000000000000000000000000000000000000',
  '000102030405060708090a0b0800000000000000000000000000000000000000',
  '000102030405060708090a0b0000000000000000000000000000000000000000',
  '000102030405060708090a0b1000000000000000000000000000000000000000',
  '000102030405060708090a0b2000000000000000000000000000000000000000',
  '000102030405060708090a0b4000000000000000000000000000000000000000',
  '000102030405060708090a0b8000000000000000000000000000000000000000',
  '000102030405060708090a0a0000000000000000000000000000000000000000',
  '000102030405060708090a080000000000000000000000000000000000000000',
  '000102030405060708090a0c0000000000000000000000000000000000000000',
  '000102030405060708090a000000000000000000000000000000000000000000',
  '000102030405060708090a100000000000000000000000000000000000000000',
  '000102030405060708090a200000000000000000000000000000000000000000',
  '000102030405060708090a400000000000000000000000000000000000000000',
  '000102030405060708090a800000000000000000000000000000000000000000',
  '000102030405060708090b000000000000000000000000000000000000000000',
  '0001020304050607080908000000000000000000000000000000000000000000',
  '000102030405060708090c000000000000000000000000000000000000000000',
  '0001020304050607080900000000000000000000000000000000000000000000',
  '0001020304050607080910000000000000000000000000000000000000000000',
  '0001020304050607080920000000000000000000000000000000000000000000',
  '0001020304050607080940000000000000000000000000000000000000000000',
  '0001020304050607080980000000000000000000000000000000000000000000',
  '0001020304050607080800000000000000000000000000000000000000000000',
  '0001020304050607080a00000000000000000000000000000000000000000000',
  '0001020304050607080c00000000000000000000000000000000000000000000',
  '0001020304050607080000000000000000000000000000000000000000000000',
  '0001020304050607081000000000000000000000000000000000000000000000',
  '0001020304050607082000000000000000000000000000000000000000000000',
  '0001020304050607084000000000000000000000000000000000000000000000',
  '0001020304050607088000000000000000000000000000000000000000000000',
  '0001020304050607090000000000000000000000000000000000000000000000',
  '00010203040506070a0000000000000000000000000000000000000000000000',
  '00010203040506070c0000000000000000000000000000000000000000000000',
  '0001020304050607000000000000000000000000000000000000000000000000',
  '0001020304050607100000000000000000000000000000000000000000000000',
  '0001020304050607200000000000000000000000000000000000000000000000',
  '0001020304050607400000000000000000000000000000000000000000000000',
  '0001020304050607800000000000000000000000000000000000000000000000',
  '0001020304050606000000000000000000000000000000000000000000000000',
  '0001020304050604000000000000000000000000000000000000000000000000',
  '0001020304050600000000000000000000000000000000000000000000000000',
  '0001020304050608000000000000000000000000000000000000000000000000',
  '0001020304050610000000000000000000000000000000000000000000000000',
  '0001020304050620000000000000000000000000000000000000000000000000',
  '0001020304050640000000000000000000000000000000000000000000000000',
  '0001020304050680000000000000000000000000000000000000000000000000',
  '0001020304050700000000000000000000000000000000000000000000000000',
  '0001020304050400000000000000000000000000000000000000000000000000',
  '0001020304050000000000000000000000000000000000000000000000000000',
  '0001020304050800000000000000000000000000000000000000000000000000',
  '0001020304051000000000000000000000000000000000000000000000000000',
  '0001020304052000000000000000000000000000000000000000000000000000',
  '0001020304054000000000000000000000000000000000000000000000000000',
  '0001020304058000000000000000000000000000000000000000000000000000',
  '0001020304040000000000000000000000000000000000000000000000000000',
  '0001020304060000000000000000000000000000000000000000000000000000',
  '0001020304000000000000000000000000000000000000000000000000000000',
  '0001020304080000000000000000000000000000000000000000000000000000',
  '0001020304100000000000000000000000000000000000000000000000000000',
  '0001020304200000000000000000000000000000000000000000000000000000',
  '0001020304400000000000000000000000000000000000000000000000000000',
  '0001020304800000000000000000000000000000000000000000000000000000',
  '0001020305000000000000000000000000000000000000000000000000000000',
  '0001020306000000000000000000000000000000000000000000000000000000',
  '0001020300000000000000000000000000000000000000000000000000000000',
  '0001020308000000000000000000000000000000000000000000000000000000',
  '0001020310000000000000000000000000000000000000000000000000000000',
  '0001020320000000000000000000000000000000000000000000000000000000',
  '0001020340000000000000000000000000000000000000000000000000000000',
  '0001020380000000000000000000000000000000000000000000000000000000',
  '0001020200000000000000000000000000000000000000000000000000000000',
  '0001020000000000000000000000000000000000000000000000000000000000',
  '0001020400000000000000000000000000000000000000000000000000000000',
  '0001020800000000000000000000000000000000000000000000000000000000',
  '0001021000000000000000000000000000000000000000000000000000000000',
  '0001022000000000000000000000000000000000000000000000000000000000',
  '0001024000000000000000000000000000000000000000000000000000000000',
  '0001028000000000000000000000000000000000000000000000000000000000',
  '0001030000000000000000000000000000000000000000000000000000000000',
  '0001000000000000000000000000000000000000000000000000000000000000',
  '0001040000000000000000000000000000000000000000000000000000000000',
  '0001080000000000000000000000000000000000000000000000000000000000',
  '0001100000000000000000000000000000000000000000000000000000000000',
  '0001200000000000000000000000000000000000000000000000000000000000',
  '0001400000000000000000000000000000000000000000000000000000000000',
  '0001800000000000000000000000000000000000000000000000000000000000',
  '0000000000000000000000000000000000000000000000000000000000000000',
  '0002000000000000000000000000000000000000000000000000000000000000',
  '0004000000000000000000000000000000000000000000000000000000000000',
  '0008000000000000000000000000000000000000000000000000000000000000',
  '0010000000000000000000000000000000000000000000000000000000000000',
  '0020000000000000000000000000000000000000000000000000000000000000',
  '0040000000000000000000000000000000000000000000000000000000000000',
  '0080000000000000000000000000000000000000000000000000000000000000',
  '0100000000000000000000000000000000000000000000000000000000000000',
  '0200000000000000000000000000000000000000000000000000000000000000',
  '0400000000000000000000000000000000000000000000000000000000000000',
  '0800000000000000000000000000000000000000000000000000000000000000',
  '1000000000000000000000000000000000000000000000000000000000000000',
  '2000000000000000000000000000000000000000000000000000000000000000',
  '4000000000000000000000000000000000000000000000000000000000000000',
  '8000000000000000000000000000000000000000000000000000000000000000'
].map(hexToByteArray);
